# -*- coding: utf-8 -*-
# created on 2018/5/15

from sympy import sympify, Union, Interval, S, solve, simplify
from mathsolver.functions.base.base import new_latex
from mathsolver.functions.base.base import BaseValue
from mathsolver.functions.base.objects import _BaseIneq, _BaseEq, _BaseEqs, _BaseIneqs
from sympy.abc import n


class BaseSequence(BaseValue):
    """ 数列 """

    def __init__(self, value):
        super(BaseSequence, self).__init__(value)
        self.type = "ShuLie"
        self.name = self.get_name()  # 类名
        self.aName = self.get_name()  # 数列通项名
        self.sName = None
        self.nName = sympify('n')  # 下标变量
        self.nRange = range(1, 10000)
        self.aRange = S.Reals  # 首项范围
        self.xRange = S.Reals  # 项的范围
        self.aValue = None
        self.an = []  # 通项公式
        self.sn = []  # 前n项和
        self.a1 = []  # 首项
        self.Eqs = []  # 数列方程
        self.otherEqs = []  # 其他数列方程
        self.Xiangs_Eqs = []  # 数列项
        self.DiTuiGongShi_Eqs = []  # 递推公式
        self.nXiangs_Eqs = []  # 含n的项
        self.DiTuiGongShi_Ineqs = []  # 递推不等式
        self.steps_TongXiang = None
        self.label_TongXiang = None
        self.steps_nSums = None
        self.label_nSums = None

    def get_name(self):
        new_value = sympify(self.value)
        name = new_value.func
        return str(name)

    def get_init(self):
        self.Eqs = []
        self.Xiangs_Eqs = []
        self.DiTuiGongShi_Eqs = []
        self.nXiangs_Eqs = []
        self.DiTuiGongShi_Ineqs = []
        self.a1 = []
        self.otherEqs = []

    def other_eqs_update(self):
        import re
        for eq in self.Eqs:
            if len(eq) == 2:
                expr = eq[0] - eq[1]
                p = r'[a-zA-Z]_\(.*?\)'
                m = re.findall(p, str(expr))
                m = set(m)
                m = list(m)
                a_name = self.aName
                s_name = self.sName
                flag = True
                if m:
                    for item in m:
                        new_item = sympify(item)
                        new_item_name = new_item.func
                        if not (str(new_item_name) == a_name or str(new_item_name) == s_name):
                            flag = False
                            break
                if not flag:
                    self.otherEqs.append(eq)
        for eq in self.otherEqs:
            self.Eqs.remove(eq)

    def eqs_update(self, eqs):
        # 更新数列相关公式
        for eq in eqs:
            if len(eq) == 2:
                self.Eqs.append([sympify(eq[0]), sympify(eq[1])])
            else:
                try:
                    left, middle, right = sympify(eq[0]), sympify(eq[1]), sympify(eq[2])
                    self.Eqs.append([left, middle])
                    self.Eqs.append([left, right])
                    self.Eqs.append([middle, right])
                except Exception:
                    self.Eqs.append([sympify(eq[0]), eq[1], sympify(eq[2])])

    def get_shouxiang(self):
        # 求数列的首项
        if self.aValue is not None:
            self.a1.append([sympify(self.aName)(1), self.aValue])
            return
        import re
        eqs = self.Eqs
        for eq in eqs:
            if len(eq) == 2:
                expr = (eq[0] - eq[1]).expand().simplify()
                p = r'[a-zA-Z]_\(.*?\)'
                m = re.findall(p, str(expr))
                m = set(m)
                m = list(m)
                a_name = self.aName
                a_name = sympify(a_name)
                if len(m) == 1 and m[0] == str(a_name(1)):
                    answer = solve(expr, simplify(m[0]))
                    if answer:
                        for ans in answer:
                            if ans.free_symbols:
                                self.a1.append([a_name(1), ans])
                            else:
                                if ans in self.xRange:
                                    self.a1.append([a_name(1), ans])
        for eq in self.a1:
            try:
                self.Eqs.remove(eq)
            except Exception:
                self.Eqs.remove([eq[0] - eq[1], S.Zero])
        if not self.a1:
            a_name = self.aName
            a_name = sympify(a_name)
            self.a1.append([a_name(1), a_name(1)])

    def get_xiangs(self):
        import re
        for eq in self.Eqs:
            if len(eq) == 2:
                expr = (eq[0] - eq[1]).expand().simplify()
                p = r'[a-zA-Z]_\(.*?\)'
                m = re.findall(p, str(expr))
                type_ = []
                if m:
                    for item in m:
                        new_item = simplify(item)
                        index = new_item.args[0]
                        symbols = index.free_symbols
                        if symbols:
                            type_.append(1)
                        else:
                            if index != 1:
                                type_.append(0)
                if type_:
                    type_sum = sum(type_)
                    if type_sum == 0:
                        self.Xiangs_Eqs.append(eq)
            else:
                expr = (eq[0] - eq[2]).expand().simplify()
                p = r'[a-zA-Z]_\(.*?\)'
                m = re.findall(p, str(expr))
                type_ = []
                if m:
                    for item in m:
                        new_item = simplify(item)
                        index = new_item.args[0]
                        symbols = index.free_symbols
                        if symbols:
                            type_.append(1)
                        else:
                            type_.append(0)
                else:
                    type_.append(1)
                if type_:
                    type_sum = sum(type_)
                    if type_sum == 0:
                        self.Xiangs_Eqs.append(eq)
        for eq in self.Xiangs_Eqs:
            self.Eqs.remove(eq)

    def get_dituigongshi(self):
        # 求数列的递推公式
        import re
        for eq in self.Eqs:
            if len(eq) == 2:
                expr = (eq[0] - eq[1]).expand().simplify()
                p = r'[a-zA-Z]_\(.*?\)'
                m = re.findall(p, str(expr))
                m = list(set(m))
                judge = []
                if m:
                    for item in m:
                        new_item = simplify(item)
                        index = new_item.args[0]
                        symbols = index.free_symbols
                        if not symbols:
                            judge.append(0)
                        else:
                            judge.append(1)
                sum_judge = sum(judge)
                if sum_judge > 0:
                    self.DiTuiGongShi_Eqs.append(eq)
        for eq in self.DiTuiGongShi_Eqs:
            self.Eqs.remove(eq)

    def get_name_by_eqs(self):
        import re
        eqs = self.Eqs
        for eq in eqs:
            expr = (eq[0] - eq[1]).expand().simplify()
            p = r'[a-zA-Z]_\(.*?\)'
            m = re.findall(p, str(expr))
            if m:
                for item in m:
                    new_item = simplify(item)
                    new_name = new_item.func
                    p2 = r'S_'
                    m2 = re.findall(p2, str(new_name))
                    if not m2:
                        self.aName = sympify(new_name)
                    else:
                        self.sName = sympify(new_name)

    def get_tongxianggongshi(self):
        # 求数列通项公式
        from mathsolver.functions.shulie.TongXiangGongShi import GetTongXiangGongShi
        stepsolver = GetTongXiangGongShi().solver(self.a1, self.Xiangs_Eqs, self.DiTuiGongShi_Eqs, self.DiTuiGongShi_Ineqs, sympify(self.aName), sympify(self.sName))
        answer = stepsolver.output[0]
        if isinstance(answer, BasePieceShuLie):
            self.an.append(answer)
        else:
            tong_xiangs = stepsolver.output[0].sympify()
            for t in tong_xiangs:
                self.an.append(t)
        self.steps_TongXiang = stepsolver.steps
        self.label_TongXiang = stepsolver.label

    def get_nxiangs(self):
        # 含n的项，但又不是递推公式的方程或不等式，如: 数列{a_{n}}的前n项和S_{n},a_{1}=2,a_{n+1}-a_{n}=3,若S_{n}=57,则n=
        import re
        for eq in self.Eqs:
            if len(eq) == 2:
                expr = (eq[0] - eq[1]).expand().simplify()
            else:
                expr = (eq[0] - eq[2]).expand().simplify()
            p = r'[a-zA-Z]_\(.*?\)'
            m = re.findall(p, str(expr))
            type_ = []
            symbols = expr.free_symbols
            if self.nName in symbols:
                if len(m) == 1:
                    new_item = sympify(m[0])
                    answers = solve(expr, new_item)
                    assert len(answers) == 1
                    answer = answers[0]
                    answer_symbols = answer.free_symbols
                    if self.nName not in answer_symbols:
                        type_.append(0)
                    else:
                        type_.append(1)
            else:
                type_.append(1)
            if type_:
                type_sum = sum(type_)
                if type_sum == 0:
                    self.nXiangs_Eqs.append(eq)
        for eq in self.nXiangs_Eqs:
            self.Eqs.remove(eq)

    def get_nineqs(self):
        # 求数列含n的不等式
        for eq in self.Eqs:
            if len(eq) == 3:
                expr = eq[0] - eq[2]
                from mathsolver.functions.shulie.Fundamental import sl_xiangs001
                expr_nxiangs = sl_xiangs001(expr)
                if expr_nxiangs:
                    self.DiTuiGongShi_Ineqs.append(eq)

    def get_nsums(self):
        from mathsolver.functions.shulie.QianNXiangHe import ShuLieQiuHe
        tong_xiangs = self.an
        for TongXiang in tong_xiangs:
            stepsolver = ShuLieQiuHe().solver([sympify(self.aName)(n), TongXiang], 1, n)
            sn = stepsolver.output[0]
            if isinstance(sn, BasePieceShuLie):
                self.sn.append(sn)
            else:
                sn = sn.sympify()
                for s in sn:
                    self.sn.append(s)
            self.steps_nSums = stepsolver.steps
            self.label_nSums = stepsolver.label


class BaseShuLieDengCha(BaseSequence):
    """
    等差数列
    """
    def __init__(self, value):
        super(BaseShuLieDengCha, self).__init__(value)
        self.type = "DengCha"
        self.dRange = S.Reals
        self.dValue = None


class BaseShuLieDengBi(BaseSequence):
    """
    等比数列
    """

    def __init__(self, value):
        super(BaseShuLieDengBi, self).__init__(value)
        self.type = "DengBi"
        self.aRange = Union(Interval(-S.Infinity, S.Zero, True, True), Interval(S.Zero, S.Infinity, True, True))  # 首项范围
        self.qRange = Union(Interval(-S.Infinity, S.Zero, True, True), Interval(S.Zero, S.Infinity, True, True))  # 公比范围
        self.xRange = Union(Interval(-S.Infinity, S.Zero, True, True), Interval(S.Zero, S.Infinity, True, True))  # 项的范围
        self.qValue = None


class BaseShuLieValue(BaseValue):
    """数列变量"""

    def __init__(self, value):
        super(BaseShuLieValue, self).__init__(value)
        new_value = {}
        for key, item in value.items():
            new_value[key] = item
        self.value = new_value


class BasePieceShuLie(BaseSequence):
    """分段数列"""

    def __init__(self, value):
        super(BasePieceShuLie, self).__init__(value)
        self.name = value["name"]
        self.var = sympify(value["var"])
        self.expression = value["expression"]
        self.value = None

    def sympify(self):
        funs = []
        f, exp = self.name, self.expression
        for e in exp:
            expr = sympify(e[0], evaluate=False)
            funs.append([f, expr, e[1]])
        return funs

    def printing(self):
        p = ''
        for f1, f2, domain in self.sympify():
            p += " %s = %s , %s 属于 %s\n" % (new_latex(f1), new_latex(f2), new_latex(self.var), new_latex(domain))
        return p


class BaseSequences(BaseValue):
    pass


class BaseSIneq(_BaseIneq):
    pass


class BaseSeqIneq(_BaseIneq):
    pass


class BaseSeqIneqs(_BaseIneqs):
    pass


class BaseSeqEqInf(_BaseEq):
    pass


class BaseSeqSeqPolys(BaseValue):
    pass


class BaseSeqEqs(_BaseEqs):
    pass


class BaseSeqEq(_BaseEq):
    pass


class BaseSeqPoly(BaseValue):
    pass


class BaseSeqInfPoly(BaseValue):
    pass


if __name__ == '__main__':
    pass
